home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume18 / mush6.4 / part06 < prev    next >
Encoding:
Internet Message Format  |  1989-03-12  |  55.2 KB

  1. Subject:  v18i028:  Mail user's shell version 6.4, Part06/19
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: Dan Heller <island!argv@sun.com>
  7. Posting-number: Volume 18, Issue 28
  8. Archive-name: mush6.4/part06
  9.  
  10.  
  11.  
  12. #! /bin/sh
  13. # This is a shell archive.  Remove anything before this line, then unpack
  14. # it by saving it into a file and typing "sh file".  To overwrite existing
  15. # files, type "sh file -c".  You can also feed this as standard input via
  16. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  17. # will see the following message at the end:
  18. #        "End of archive 6 (of 19)."
  19. # Contents:  curs_io.c pick.c select.c viewopts.c
  20. # Wrapped by rsalz@papaya.bbn.com on Mon Mar 13 19:25:12 1989
  21. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  22. if test -f 'curs_io.c' -a "${1}" != "-c" ; then 
  23.   echo shar: Will not clobber existing file \"'curs_io.c'\"
  24. else
  25. echo shar: Extracting \"'curs_io.c'\" \(12588 characters\)
  26. sed "s/^X//" >'curs_io.c' <<'END_OF_FILE'
  27. X/* @(#)curs_io.c    (c) copyright 3/18/87 (Dan Heller) */
  28. X
  29. X/* curs_io.c -- curses based I/O */
  30. X#include "mush.h"
  31. X#include "bindings.h"
  32. X
  33. Xstatic backspace();
  34. X
  35. Xchar *_unctrl[] = {
  36. X    "^@", "^A", "^B", "^C", "^D", "^E", "^F", "^G", "^H", "^I", "^J", "^K",
  37. X    "^L", "^M", "^N", "^O", "^P", "^Q", "^R", "^S", "^T", "^U", "^V", "^W",
  38. X    "^X", "^Y", "^Z", "^[", "^\\", "^]", "^~", "^_",
  39. X    " ", "!", "\"", "#", "$",  "%", "&", "'", "(", ")", "*", "+", ",", "-",
  40. X    ".", "/", "0",  "1", "2",  "3", "4", "5", "6", "7", "8", "9", ":", ";",
  41. X    "<", "=", ">",  "?", "@",  "A", "B", "C", "D", "E", "F", "G", "H", "I",
  42. X    "J", "K", "L",  "M", "N",  "O", "P", "Q", "R", "S", "T", "U", "V", "W",
  43. X    "X", "Y", "Z",  "[", "\\", "]", "^", "_", "`", "a", "b", "c", "d", "e",
  44. X    "f", "g", "h",  "i", "j",  "k", "l", "m", "n", "o", "p", "q", "r", "s",
  45. X    "t", "u", "v",  "w", "x",  "y", "z", "{", "|", "}", "~", "^?"
  46. X};
  47. X
  48. Xchar    del_line;    /* tty delete line character */
  49. Xchar    del_word;    /* tty delete word character */
  50. Xchar    del_char;    /* backspace */
  51. Xchar    reprint_line;    /* usually ^R */
  52. Xchar    eofc;        /* usually ^D */
  53. Xchar    lit_next;    /* usually ^V */
  54. X
  55. Xtty_settings()
  56. X{
  57. X    savetty();
  58. X
  59. X#ifdef SYSV
  60. X    eofc = _tty.c_cc[VEOF];
  61. X#else
  62. X#ifdef BSD
  63. X    if (ioctl(0, TIOCGETC, &tchars) != -1)
  64. X    eofc = tchars.t_eofc;
  65. X    else
  66. X#endif /* BSD */
  67. X    eofc = CTRL(D);
  68. X#endif /* SYSV */
  69. X
  70. X    if (!isatty(0)) {
  71. X    del_line = CTRL(U);
  72. X    del_char = CTRL(H);
  73. X    } else {
  74. X    del_line = _tty.sg_kill;
  75. X    del_char = _tty.sg_erase;
  76. X    }
  77. X
  78. X#ifdef TIOCGLTC
  79. X    if (ioctl(0, TIOCGLTC, <chars) != -1) {
  80. X    del_word = ltchars.t_werasc;
  81. X    reprint_line = ltchars.t_rprntc;
  82. X    lit_next = ltchars.t_lnextc;
  83. X    } else
  84. X#endif /* TIOCGLTC */
  85. X    {
  86. X    del_word = CTRL(W);
  87. X    reprint_line = CTRL(R);
  88. X    lit_next = CTRL(V);
  89. X    }
  90. X}
  91. X
  92. X#ifdef Addch
  93. X#undef Addch
  94. X#endif /* Addch */
  95. X
  96. X#ifndef CURSES
  97. X
  98. X/* Make sure all ifs have matching elses! */
  99. X
  100. X#define Addch(c) \
  101. X    if (ison(glob_flags, ECHO_FLAG)) \
  102. X    {;} \
  103. X    else \
  104. X    fputc(c, stdout), fflush(stdout)
  105. X
  106. X#else
  107. X
  108. X/* see end of Getstr */
  109. X#define Addch(c)  \
  110. X    if (iscurses) \
  111. X    addch(c), refresh(); \
  112. X    else if (ison(glob_flags, ECHO_FLAG)) \
  113. X    {;} \
  114. X    else \
  115. X    fputc(c, stdout), fflush(stdout)
  116. X#endif /* CURSES */
  117. X
  118. X/*
  119. X * get a string of at most 'length' chars.
  120. X * allow backspace-space-backspace, kill word and kill line
  121. X * (options set by user in stty).
  122. X * length is the max length this string can get. offset is from beginning
  123. X * of string.
  124. X * input of ^D returns -1; otherwise, return the number of chars in string.
  125. X */
  126. XGetstr(String, length, offset)
  127. Xchar String[];
  128. Xregister int length;
  129. X{
  130. X    register int c, literal_next = FALSE, lit_bs = FALSE;
  131. X    struct cmd_map *curr_map;
  132. X    int count = offset, save_wc = wrapcolumn;
  133. X
  134. X    fflush(stdout); /* make sure everything is flushed before getting input */
  135. X
  136. X    if (mac_hide) {
  137. X    curr_map = NULL_MAP;
  138. X    wrapcolumn = 0;
  139. X    } else if (ison(glob_flags, IS_GETTING))
  140. X    curr_map = bang_map;
  141. X    else if (iscurses)
  142. X    curr_map = NULL_MAP;
  143. X    else
  144. X    curr_map = line_map;
  145. X
  146. X    while ((c = m_getchar()) != '\n' && c != '\r' && c != EOF &&
  147. X        isoff(glob_flags, WAS_INTR)) {
  148. X    /* echo isn't set, so whatever the character, enter it */
  149. X    if (ison(glob_flags, QUOTE_MACRO) || ison(glob_flags, ECHO_FLAG)) {
  150. X        if (count < length) {
  151. X        String[count++] = c;
  152. X        /* Note: Addch includes ECHO_FLAG test */
  153. X        if (iscntrl(c)) {
  154. X            Addch('^');
  155. X            Addch(_unctrl[c][1]);
  156. X        } else
  157. X            Addch(c);
  158. X        } else {
  159. X        print("Warning: string too long. Truncated at %d chars.\n",
  160. X            length);
  161. X        break;
  162. X        }
  163. X    }
  164. X    /* ^D as the first char on a line or two ^D's in a row is EOF */
  165. X    else if (c == eofc && !count)
  166. X        break;
  167. X    else if (c == '\\' && count < length) {
  168. X        literal_next = TRUE, lit_bs = FALSE;
  169. X        Addch(String[count++] = '\\');
  170. X        } else if (c == lit_next && count < length) {
  171. X        literal_next = lit_bs = TRUE;
  172. X        String[count++] = '\\';
  173. X        if (!in_macro()) {
  174. X        /* if (iscntrl(c)) */
  175. X            Addch('^');
  176. X        /* Addch(_unctrl[c][1]); */
  177. X        }
  178. X    } else if (literal_next) {
  179. X        struct cmd_map *list;
  180. X
  181. X        literal_next = FALSE;
  182. X        if (iscntrl(c) || c == del_line || c == del_char || c == del_word
  183. X            || c == lit_next || lit_bs)
  184. X        if (!in_macro() || !lit_bs)
  185. X            backspace(String, &count);
  186. X        else
  187. X            --count;
  188. X        else if (in_macro() && c == MAC_LONG_CMD)
  189. X        --count;
  190. X        /* check to see if user is escaping a map or map! */
  191. X        else
  192. X        for (list = curr_map; list; list = list->m_next)
  193. X            if (list->m_str[0] == c) {
  194. X            if (!in_macro())
  195. X                backspace(String, &count);
  196. X            else
  197. X                --count;
  198. X            break;
  199. X            }
  200. X        /* A literal-next advances the macro offset */
  201. X        String[count++] = c;
  202. X        if (iscntrl(c) || c == del_char) {
  203. X        if (iscntrl(c)) {
  204. X            /*
  205. X             * Decrement wrapcolumn because two chars added.
  206. X             * It will be restored from save_wc before return.
  207. X             */
  208. X            if (wrapcolumn > 1)
  209. X            wrapcolumn--;
  210. X            Addch('^');
  211. X        }
  212. X        Addch(_unctrl[c][1]);
  213. X        } else
  214. X        Addch(c);
  215. X    } else if (c == del_line) {
  216. X        if (count) {
  217. X        do
  218. X            backspace(String, &count);
  219. X        while (count);
  220. X        }
  221. X    } else
  222. X    if (c == reprint_line)
  223. X        String[count] = 0, wprint("\n%s", String);
  224. X        else
  225. X    if (c == del_word) /* word erase */
  226. X        while (count) {
  227. X        backspace(String, &count);
  228. X        if (!count ||
  229. X            isspace(String[count-1]) && !isspace(String[count]) ||
  230. X            !isalnum(String[count-1]) && isalnum(String[count]))
  231. X            break;
  232. X        }
  233. X    else if (c == del_char || c == CTRL(H) || c == 127 /* CTRL(?) */) {
  234. X        if (count)
  235. X        backspace(String, &count);
  236. X        /* if iscurses, then backspacing too far cancels a function */
  237. X        else if (!count && iscurses && isoff(glob_flags, LINE_MACRO)) {
  238. X        mac_flush();
  239. X        String[0] = '\0';
  240. X        wrapcolumn = save_wc;
  241. X        return -1;
  242. X        }
  243. X    } else if (count == length)
  244. X        bell();
  245. X    else if (c == '\t')
  246. X        do  {
  247. X        /* Yuck -- tabs break map! */
  248. X        Addch(' ');
  249. X        String[count] = ' ';
  250. X        } while (++count % 8 && count < length);
  251. X    else if (in_macro() && c == MAC_LONG_CMD) {
  252. X        char cbuf[MAX_LONG_CMD + 1];
  253. X
  254. X        if ((c = read_long_cmd(cbuf)) == 0) {
  255. X        c = MAC_LONG_CMD;
  256. X        goto check_expand;    /* How could I avoid this? */
  257. X        } else if (c > 0) {
  258. X        int ok;
  259. X
  260. X        String[count] = '\0';
  261. X        if ((ok = reserved_cmd(cbuf, TRUE)) > 0) {
  262. X            /* Reprint the line */
  263. X            if (iscurses)
  264. X            print(":%s", String);
  265. X            else
  266. X            wprint("\r%s", String);
  267. X            continue;    /* Get next char without changing count */
  268. X        } else if (ok < 0) {
  269. X            String[offset] = '\0';
  270. X            wrapcolumn = save_wc;
  271. X            return ok;
  272. X        } else
  273. X            goto push_back;
  274. X        } else {
  275. X        /*
  276. X         * Ooops.  We read a bunch of stuff we should not
  277. X         * have read, because this isn't really a long command.
  278. X         * Use a trick to push the whole thing back, ala ungetc.
  279. X         * Wouldn't it be nifty if stdio worked this way? :-)
  280. X         */
  281. Xpush_back:
  282. X        if (c > 0) {
  283. X            cbuf[c++] = MAC_LONG_END;
  284. X            cbuf[c] = '\0';
  285. X        }
  286. X        c = MAC_LONG_CMD;
  287. X        Ungetstr(cbuf);
  288. X        goto check_expand;    /* How could I avoid this goto? */
  289. X        }
  290. X    } else {
  291. Xcheck_expand:
  292. X        if (!curr_map || !check_map(c, curr_map)) {
  293. X        /* else if (match != MATCH) */
  294. X        if (c != '\t' && iscntrl(c)) {
  295. X            Addch('^');
  296. X            Addch(_unctrl[c][1]);
  297. X            /* Decrement wrapcolumn as above */
  298. X            if (wrapcolumn > 1)
  299. X            wrapcolumn--;
  300. X        } else
  301. X            Addch(c);
  302. X        String[count++] = c;
  303. X        }
  304. X    }
  305. X    /* Null-terminate for macro lookup purposes.
  306. X     * This will be overwritten by the next character.
  307. X     */
  308. X    String[count] = '\0';
  309. X    if (line_wrap(String, &count))
  310. X        break;
  311. X    }
  312. X    fflush(stdout); /* for sys-v folks */
  313. X
  314. X    if (c == eofc || c == EOF || ison(glob_flags, WAS_INTR)) {
  315. X    if (feof(stdin))
  316. X        clearerr(stdin);
  317. X    wrapcolumn = save_wc;
  318. X    return -1;
  319. X    }
  320. X    if (count && String[count-1] == '\\') {
  321. X    int count2;
  322. X    if (isoff(glob_flags, ECHO_FLAG))
  323. X        putchar('\n');
  324. X    wrapcolumn = save_wc;
  325. X    /*
  326. X     * NOTE: If the offset passed here is ever made greater than 0,
  327. X     * the value of wrapcolumn must again be changed/restored ...
  328. X     */
  329. X    if ((count2 = Getstr(&String[count-1], length - count + 1, 0)) == -1)
  330. X        return -1;
  331. X    return count + count2;
  332. X    }
  333. X    if (!iscurses && isoff(glob_flags, ECHO_FLAG))
  334. X    putchar('\n');
  335. X    /* Should be null-terminated already, but just in case */
  336. X    String[count] = '\0';
  337. X    wrapcolumn = save_wc;
  338. X    return count;
  339. X}
  340. X
  341. Xstatic
  342. Xbackspace(str, n)
  343. Xregister char *str;
  344. Xint *n;
  345. X{
  346. X    (*n)--;
  347. X    Addch('\b'); Addch(' '); Addch('\b');
  348. X    if (iscntrl(str[*n])) {
  349. X    Addch('\b'); Addch(' '); Addch('\b');
  350. X    /* Re-increment wrapcolumn -- see Getstr */
  351. X    if (wrapcolumn)
  352. X        wrapcolumn++;
  353. X    }
  354. X}
  355. X
  356. X#undef Addch
  357. X
  358. X/*
  359. X * Check to see if what the user is typing is supposed to be expanded
  360. X * into a longer string.  The first char is 'c' and the map list to use
  361. X * is in map_list.  Continue looping (reading chars from stdin or a
  362. X * currently active mapping) until a match happens or we've determined
  363. X * that there is no match.
  364. X */
  365. Xcheck_map(c, map_list)
  366. Xchar c;
  367. Xstruct cmd_map *map_list;
  368. X{
  369. X    char mbuf[MAX_MACRO_LEN], *p = mbuf;
  370. X    struct cmd_map *list;
  371. X    int m, n, match;
  372. X
  373. X    *p++ = c;
  374. X
  375. X    while (isoff(glob_flags, WAS_INTR)) {
  376. X    m = 0;
  377. X    *p = 0; /* make sure it's null terminated */
  378. X    /*
  379. X     * loop thru the list of maps and check to see if the typed
  380. X     * char matches the mapping.  If it matches completely, substitute
  381. X     * the stuff in x_str and return.  If a partial match occurs, then
  382. X     * read the next char until a timeout or no match.
  383. X     */
  384. X    for (list = map_list; list; list = list->m_next) {
  385. X        if ((match = prefix(mbuf, list->m_str)) == MATCH) {
  386. X        /* Must turn on flags BEFORE pushing */
  387. X        line_macro(list->x_str);
  388. X        return 1;
  389. X        } else if (match != NO_MATCH)
  390. X        m++; /* something matched partially */
  391. X    }
  392. X    if (!m)
  393. X        break;
  394. X    /* see if there's anything on the queue to read... */
  395. X    if (mac_pending()
  396. X#ifdef FIONREAD
  397. X        || !ioctl(0, FIONREAD, &n) && n > 0
  398. X#endif /* FIONREAD */
  399. X                           )
  400. X        *p++ = m_getchar();
  401. X    else {
  402. X    /* The user has typed the first part of a map or macro.  Give him
  403. X     * a chance to finish it.
  404. X     */
  405. X#if defined(BSD) || defined(SELECT)
  406. X        /* If the system has select(), use it.  It's much faster and
  407. X         * more aesthetic since there is no mandatory timeout.
  408. X         */
  409. X        struct timeval timer;
  410. X#ifdef FD_SET
  411. X        fd_set rmask, wmask, xmask;
  412. X        FD_SET(0, &rmask);    /* Test stdin for read */
  413. X        FD_ZERO(&wmask);    /* Don't care about write */
  414. X        FD_ZERO(&xmask);    /* Don't care about exception */
  415. X#else
  416. X        int rmask = 1, wmask = 0, xmask = 0;
  417. X#endif /* FD_SET */
  418. X        timer.tv_sec = 1;
  419. X        timer.tv_usec = 0;
  420. X        n = select(1, &rmask, &wmask, &xmask, &timer);
  421. X#else /* !SELECT */
  422. X#ifdef FIONREAD
  423. X        /* system doesn't have select(), so use FIONREAD to see if
  424. X         * there are any chars on the queue to read.
  425. X         */
  426. X        (void) sleep(1);
  427. X        (void) ioctl(0, FIONREAD, &n);
  428. X#else
  429. X        /* system has neither select() nor FIONREAD, so just set n
  430. X         * and force the user to either complete the map or fail it
  431. X         * without a timeout.  Chars won't echo till he does one or
  432. X         * the other.
  433. X         */
  434. X        n = 1;
  435. X#endif /* FIONREAD */
  436. X#endif /* SELECT */
  437. X        if (n > 0)
  438. X        /* don't read all 'n' chars -- there may be a match early */
  439. X        *p++ = m_getchar();    /* To flush macros and reset flags */
  440. X        else /* still nothing to read? User doesn't want to use map */
  441. X        break;
  442. X    }
  443. X    }
  444. X    /* no match or a timeout.  This isn't a map, just return. */
  445. X    *p = 0;
  446. X    if (mbuf[1])
  447. X    mac_push(mbuf + 1);
  448. X    return 0;
  449. X}
  450. X
  451. X/*
  452. X * Check for line wrap.  This should happen only in composition mode and
  453. X * only when the variable wrapcolumn has a value greater than zero.  Line
  454. X * wrap is implemented using Ungetstr [that is, mac_push()].
  455. X *
  456. X * Returns 1 if the line was wrapped, 0 if not.
  457. X */
  458. Xline_wrap(string, count)
  459. Xchar *string;    /* The string to be wrapped */
  460. Xint *count;    /* Offset of string terminator */
  461. X{
  462. X    char *tail = NULL;
  463. X    int n = *count;
  464. X
  465. X    if (wrapcolumn < 1 || *count <= wrapcolumn
  466. X        || isoff(glob_flags, IS_GETTING)    /* Wrap only in msg body */
  467. X        || ison(glob_flags, QUOTE_MACRO)    /* Don't wrap quoted macros */
  468. X        || ison(glob_flags, ECHO_FLAG))    /* Can't wrap in echo mode */
  469. X    return 0;
  470. X
  471. X    /* Back up past the wrapcolumn point */
  472. X    for (; n > wrapcolumn; --n)
  473. X        ;
  474. X    /* Look for a space */
  475. X    while (n && !isspace(string[n]))
  476. X    --n;
  477. X    /* If no break found, return no wrap */
  478. X    if (!n)
  479. X    return 0;
  480. X    tail = &string[n+1];
  481. X    /* Skip the break char and any whitespace */
  482. X    while (n && isspace(string[n]))
  483. X    --n;
  484. X    ++n; /* move back into the whitespace */
  485. X    /* Erase the stuff that will wrap */
  486. X    while (*count > n)
  487. X    backspace(string,count);
  488. X    string[*count] = '\0';
  489. X    /* Push the tail, if any */
  490. X    if (*tail)
  491. X    Ungetstr(tail);
  492. X    return 1;
  493. X}
  494. END_OF_FILE
  495. if test 12588 -ne `wc -c <'curs_io.c'`; then
  496.     echo shar: \"'curs_io.c'\" unpacked with wrong size!
  497. fi
  498. # end of 'curs_io.c'
  499. fi
  500. if test -f 'pick.c' -a "${1}" != "-c" ; then 
  501.   echo shar: Will not clobber existing file \"'pick.c'\"
  502. else
  503. echo shar: Extracting \"'pick.c'\" \(13226 characters\)
  504. sed "s/^X//" >'pick.c' <<'END_OF_FILE'
  505. X/* @(#)pick.c    2.4    (c) copyright 10/18/86 (Dan Heller) */
  506. X
  507. X#include "mush.h"
  508. X
  509. Xstatic int before, after, search_from, search_subj, search_to, xflg, icase;
  510. Xstatic mdy[3], search_hdr[64];
  511. Xstatic int pick();
  512. X
  513. Xdo_pick(n, argv, list)
  514. Xregister int n;
  515. Xregister char **argv, list[];
  516. X{
  517. X    char ret_list[MAXMSGS_BITS];
  518. X
  519. X    if (n > 1 && !strcmp(argv[1], "-?"))
  520. X    return help(0, "pick", cmd_help);
  521. X
  522. X    /* if is_pipe, then the messages to search for are already set.
  523. X     * if not piped, then reverse the bits for all message numbers.
  524. X     * That is, search EACH message. only those matching will be returned.
  525. X     */
  526. X    if (isoff(glob_flags, IS_PIPE))
  527. X    bitput(list, list, msg_cnt, =~) /* macro, turn on all bits */
  528. X    clear_msg_list(ret_list);
  529. X    if (pick(n, argv, list, ret_list, isoff(glob_flags, DO_PIPE)) == -1)
  530. X    return -1;
  531. X    if (istool && isoff(glob_flags, DO_PIPE))
  532. X    print("Messages: ");
  533. X    for (n = 0; n < msg_cnt; n++)
  534. X    if (msg_bit(ret_list, n) && !xflg ||
  535. X        !msg_bit(ret_list, n) && xflg) {
  536. X        if (isoff(glob_flags, DO_PIPE))
  537. X        if (istool)
  538. X            print_more("%d ", n+1);
  539. X        else
  540. X            print("%s\n", compose_hdr(n));
  541. X        set_msg_bit(list, n);
  542. X    } else
  543. X        unset_msg_bit(list, n);
  544. X    return 0;
  545. X}
  546. X
  547. X/*
  548. X * search for messages.  Even if no messages match, return 0.  Errors such
  549. X * as internal errors or syntax errors, return -1.
  550. X */
  551. Xstatic int
  552. Xpick(ret, argv, list, ret_list, verbose)
  553. Xregister int ret;
  554. Xregister char **argv, list[], ret_list[];
  555. X{
  556. X    register char c;
  557. X    char pattern[256];
  558. X    int o_before = before, o_after = after, o_search_from = search_from,
  559. X    o_search_subj = search_subj, o_search_to = search_to, o_mdy[3], n;
  560. X
  561. X    for (c = 0; c < 3; c++)
  562. X    o_mdy[c] = mdy[c];
  563. X
  564. X    ret = -1;
  565. X    if (!msg_cnt) {
  566. X    print("No Messages.\n");
  567. X    goto bad;
  568. X    }
  569. X
  570. X    icase = before = after = search_from = search_subj = xflg = 0;
  571. X    mdy[0] = search_hdr[0] = 0;
  572. X    while (*argv && *++argv && **argv == '-')
  573. X    switch(c = argv[0][1]) {
  574. X        /* users specifies a range */
  575. X        case 'r': {
  576. X        int X = 2;
  577. X        /* if not a pipe, then clear all bits cuz we only want
  578. X         * to search the message specified here...
  579. X         * If it is a pipe, then add to the messages searched for.
  580. X         */
  581. X        if (isoff(glob_flags, IS_PIPE))
  582. X            clear_msg_list(list);
  583. X        /*  "-r10-15"
  584. X         *     ^argv[1][2]  if NULL, then
  585. X         * list detached from "r" e.g. "-r" "5-20"
  586. X         */
  587. X        if (!argv[0][X])
  588. X            argv++, X = 0;
  589. X        (*argv) += X;
  590. X        n = get_msg_list(argv, list);
  591. X        (*argv) -= X;
  592. X        if (n == -1)
  593. X            goto bad;
  594. X        argv += (n-1); /* we're going to increment another up top */
  595. X        }
  596. X        when 'a': {
  597. X        if ((n = ago_date(++argv)) == -1)
  598. X            goto bad;
  599. X        argv += n;
  600. X        }
  601. X        when 'd':
  602. X        if (!*++argv) {
  603. X            print("specify a date for -%c\n", c);
  604. X            goto bad;
  605. X        }
  606. X        if (!date1(*argv))
  607. X            goto bad;
  608. X        when 's' : case 'f': case 't': case 'h':
  609. X        if (search_subj + search_from + search_to + *search_hdr > 1) {
  610. X            print("specify one of `s', `f', `t' or `h' only\n");
  611. X            goto bad;
  612. X            }
  613. X            if (c == 's')
  614. X            search_subj = 1;
  615. X        else if (c == 'f')
  616. X            search_from = 1;
  617. X        else if (c == 'h')
  618. X            if (!*++argv)
  619. X            print("Specify header to search for.\n");
  620. X            else
  621. X            (void) lcase_strcpy(search_hdr, *argv);
  622. X        else
  623. X            search_to = 1;
  624. X        when 'x' : xflg = 1;
  625. X        when 'i' : icase = 1;
  626. X        otherwise:
  627. X        print("pick: unknown flag: %c\n", argv[0][1]);
  628. X        clear_msg_list(ret_list);
  629. X        return -1;
  630. X    }
  631. X    pattern[0] = 0;
  632. X    (void) argv_to_string(pattern, argv);
  633. X    if (verbose) {
  634. X    print_more("Searching for messages");
  635. X    if (mdy[1] == 0) {
  636. X        print(" that %scontain \"%s\"", (xflg)? "does not ": "",
  637. X                (*pattern)? pattern: "<previous expression>");
  638. X        if (search_subj)
  639. X        print_more(" in subject line");
  640. X        else if (search_from)
  641. X        print_more(" from author names");
  642. X        else if (search_to)
  643. X        print_more(" from the To: field");
  644. X        else if (search_hdr[0])
  645. X        print_more(" from the message header: \"%s:\"", search_hdr);
  646. X    } else {
  647. X        extern char *month_names[]; /* from dates.c */
  648. X        print_more(" dated ");
  649. X        if (before || after)
  650. X        if (xflg)
  651. X            print_more("%s ", (!before)? "before": "after");
  652. X        else
  653. X            print_more("on or %s ", (before)? "before": "after");
  654. X        print_more("%s. %d, 19%d.",
  655. X              month_names[mdy[0]], mdy[1], mdy[2]);
  656. X    }
  657. X    print_more("\n");
  658. X    }
  659. X    if (mdy[1] > 0 && icase)
  660. X    print("using date: -i flag ignored.\n");
  661. X    ret = find_pattern(pattern, list, ret_list);
  662. Xbad:
  663. X    before = o_before, after = o_after, search_from = o_search_from;
  664. X    search_subj = o_search_subj, search_to = o_search_to;
  665. X    for (c = 0; c < 3; c++)
  666. X    mdy[c] = o_mdy[c];
  667. X
  668. X    return ret;
  669. X}
  670. X
  671. Xfind_pattern(p, check_list, ret_list)
  672. Xregister char *p;
  673. Xchar check_list[], ret_list[];
  674. X{
  675. X    register int n, val, i; /* val is return value from regex or re_exec */
  676. X    long bytes = 0;
  677. X    char buf[HDRSIZ];
  678. X    static char *err = (char *)-1;
  679. X#ifdef REGCMP
  680. X    char *regcmp(), *regex();
  681. X#else /* REGCMP */
  682. X    char *re_comp();
  683. X#endif /* REGCMP */
  684. X
  685. X    if (p && *p == '\\')
  686. X    p++;  /* take care of escaping special cases (`-', `\') */
  687. X
  688. X    /* specify what we're looking for */
  689. X    if (p && *p) {
  690. X    if (icase)
  691. X        p = lcase_strcpy(buf, p);
  692. X#ifdef REGCMP
  693. X    if (err && p)
  694. X        xfree(err);
  695. X    if (p && !(err = regcmp(p, NULL))) {
  696. X        print("regcmp error: %s\n", p);
  697. X        clear_msg_list(ret_list);
  698. X        return -1;
  699. X    }
  700. X#else /* REGCMP */
  701. X    if (err = re_comp(p)) {
  702. X        print("re_comp error: %s\n", err);
  703. X        clear_msg_list(ret_list);
  704. X        return -1;
  705. X    }
  706. X#endif /* REGCMP */
  707. X    } else if (err == (char *)-1 && mdy[1] <= 0) {
  708. X    print("No previous regular expression\n");
  709. X    clear_msg_list(ret_list);  /* doesn't matter really */
  710. X    return -1;
  711. X    }
  712. X    /* start searching: set bytes, and message number: n */
  713. X    for (n = 0; n < msg_cnt; n++)
  714. X    if (msg_bit(check_list, n)) {
  715. X        if (mdy[1] > 0) {
  716. X        int msg_mdy[3];
  717. X        if (ison(glob_flags, DATE_RECV))
  718. X            p = msg[n].m_date_recv;
  719. X        else
  720. X            p = msg[n].m_date_sent;
  721. X        (void) sscanf(p, "%2d%2d%2d", /* yr mo da */
  722. X             &msg_mdy[2], &msg_mdy[0], &msg_mdy[1]);
  723. X        msg_mdy[0]--;
  724. X        Debug("checking %d's date: %d-%d-%d  ",
  725. X                 n+1, msg_mdy[0]+1, msg_mdy[1], msg_mdy[2]);
  726. X        /* start at year and wrap around.
  727. X         * only when match the day (4), check for == (match)
  728. X         */
  729. X        for (i = 2; i < 5; i++)
  730. X            if (before && msg_mdy[i%3] < mdy[i%3]
  731. X            ||  after  && msg_mdy[i%3] > mdy[i%3]
  732. X            ||  i == 4 && (msg_mdy[i%3] == mdy[i%3])) {
  733. X                Debug("matched (%s).\n",
  734. X                (i == 2)? "year" : (i == 3)? "month" : "day");
  735. X                set_msg_bit(ret_list, n);
  736. X                break;
  737. X            } else if (msg_mdy[i%3] != mdy[i%3]) {
  738. X            Debug("failed.\n");
  739. X            break;
  740. X            }
  741. X        continue;
  742. X        }
  743. X        /* we must have the right date -- if we're searching for a
  744. X         * string, find it.
  745. X         */
  746. X        (void) msg_get(n, NULL, 0);
  747. X        bytes = 0;
  748. X        while (bytes < msg[n].m_size) {
  749. X        if (!search_subj && !search_from && !search_to &&
  750. X            !*search_hdr && !(p = fgets(buf, sizeof buf, tmpf)))
  751. X            break;
  752. X        else if (search_subj) {
  753. X            if (!(p = header_field(n, "subject")))
  754. X            break;
  755. X        } else if (search_from) {
  756. X            if (!(p = header_field(n, "from"))) {
  757. X            /*
  758. X             * Check for MSG_SEPARATOR here?  Maybe not...
  759. X             */
  760. X            register char *p2;
  761. X            (void) msg_get(n, NULL, 0);
  762. X            if (!(p2 = fgets(buf, sizeof buf, tmpf)) ||
  763. X                !(p = index(p2, ' ')))
  764. X                continue;
  765. X            p++;
  766. X            if (p2 = any(p, " \t"))
  767. X                *p2 = 0;
  768. X            }
  769. X        } else if (search_to) {
  770. X            if (!(p = header_field(n, "to")) &&
  771. X                !(p = header_field(n, "apparently-to")))
  772. X            break;
  773. X        } else if (*search_hdr) {
  774. X            if (!(p = header_field(n, search_hdr)))
  775. X            break;
  776. X        }
  777. X        if (icase)
  778. X            p = lcase_strcpy(buf, p);
  779. X#ifdef REGCMP
  780. X        val = !!regex(err, p, NULL); /* convert value to a boolean */
  781. X#else /* REGCMP */
  782. X        val = re_exec(p);
  783. X#endif /* REGCMP */
  784. X        if (val == -1) {   /* doesn't apply in system V */
  785. X            print("Internal error for pattern search.\n");
  786. X            clear_msg_list(ret_list); /* it doesn't matter, really */
  787. X            return -1;
  788. X        }
  789. X        if (!val)
  790. X            bytes += strlen(p);
  791. X        else {
  792. X            set_msg_bit(ret_list, n);
  793. X            break;
  794. X        }
  795. X        if (search_subj || search_from || search_to || *search_hdr)
  796. X            break;
  797. X        }
  798. X    }
  799. X    return 0;
  800. X}
  801. X
  802. X#ifdef CURSES
  803. X/*
  804. X * search for a pattern in composed message headers -- also see next function
  805. X * flags ==  0   forward search (prompt).
  806. X * flags == -1   continue search (no prompt).
  807. X * flags ==  1   backward search (prompt).
  808. X */
  809. Xsearch(flags)
  810. Xregister int flags;
  811. X{
  812. X    register char   *p;
  813. X    char           pattern[128];
  814. X    register int    this_msg = current_msg, val = 0;
  815. X    static char     *err = (char *)-1, direction;
  816. X    SIGRET        (*oldint)(), (*oldquit)();
  817. X#ifdef REGCMP
  818. X    char *regcmp();
  819. X#else /* REGCMP */
  820. X    char *re_comp();
  821. X#endif /* REGCMP */
  822. X
  823. X    if (msg_cnt <= 1) {
  824. X    print("Not enough messages to invoke a search.\n");
  825. X    return 0;
  826. X    }
  827. X    pattern[0] = '\0';
  828. X    if (flags == -1)
  829. X    print("continue %s search...", direction? "forward" : "backward");
  830. X    else
  831. X    print("%s search: ", flags? "backward" : "forward");
  832. X    if (flags > -1)
  833. X    if (Getstr(pattern, COLS-18, 0) < 0)
  834. X        return 0;
  835. X    else
  836. X        direction = !flags;
  837. X#ifdef REGCMP
  838. X    if (err && *pattern)
  839. X    xfree(err);
  840. X    else if (err == (char *)-1 && !*pattern) {
  841. X    print("No previous regular expression.");
  842. X    return 0;
  843. X    }
  844. X    if (*pattern && !(err = regcmp(pattern, NULL))) {
  845. X    print("Error in regcmp in %s", pattern);
  846. X    return 0;
  847. X    }
  848. X#else /* REGCMP */
  849. X    if (err = re_comp(pattern)) {
  850. X    print(err);
  851. X    return 0;
  852. X    }
  853. X#endif /* REGCMP */
  854. X    move(LINES-1, 0), refresh();
  855. X    on_intr();
  856. X
  857. X    do  {
  858. X    if (direction)
  859. X        current_msg = (current_msg+1) % msg_cnt;
  860. X    else
  861. X        if (--current_msg < 0)
  862. X        current_msg = msg_cnt-1;
  863. X        p = compose_hdr(current_msg);
  864. X#ifdef REGCMP
  865. X    val = !!regex(err, p, NULL); /* convert value to a boolean */
  866. X#else /* REGCMP */
  867. X    val = re_exec(p);
  868. X#endif /* REGCMP */
  869. X    if (val == -1)     /* doesn't apply in system V */
  870. X        print("Internal error for pattern search.\n");
  871. X    } while (!val && current_msg != this_msg && isoff(glob_flags, WAS_INTR));
  872. X
  873. X    if (ison(glob_flags, WAS_INTR)) {
  874. X    print("Pattern search interrupted.");
  875. X    current_msg = this_msg;
  876. X    } else if (val == 0)
  877. X    print("Pattern not found.");
  878. X
  879. X    off_intr();
  880. X    return val;
  881. X}
  882. X#endif /* CURSES */
  883. X
  884. X/*
  885. X * parse a user given date string and set mdy[] array with correct
  886. X * values.  Return 0 on failure.
  887. X */
  888. Xdate1(p)
  889. Xregister char *p;
  890. X{
  891. X    register char *p2;
  892. X    long      t;
  893. X    int       i;
  894. X    struct tm       *today;
  895. X
  896. X    if (*p == '-' || *p == '+') {
  897. X    before = !(after = *p == '+');
  898. X    skipspaces(1);
  899. X    }
  900. X    if (!isdigit(*p) && *p != '/') {
  901. X    print("syntax error on date: \"%s\"\n", p);
  902. X    return 0;
  903. X    }
  904. X    (void) time (&t);
  905. X    today = localtime(&t);
  906. X    for (i = 0; i < 3; i++)
  907. X    if (!p || !*p || *p == '/') {
  908. X        switch(i) {   /* default to today's date */
  909. X        case 0: mdy[0] = today->tm_mon;
  910. X        when 1: mdy[1] = today->tm_mday;
  911. X        when 2: mdy[2] = today->tm_year;
  912. X        }
  913. X        if (p && *p)
  914. X        p++;
  915. X    } else {
  916. X        p2 = (*p)? index(p+1, '/') : NULL;
  917. X        mdy[i] = atoi(p); /* atoi will stop at the '/' */
  918. X        if (i == 0 && (--(mdy[0]) < 0 || mdy[0] > 11)) {
  919. X        print("Invalid month: %s\n", p);
  920. X        return 0;
  921. X        } else if (i == 1 && (mdy[1] < 1 || mdy[1] > 31)) {
  922. X        print("Invalid day: %s\n", p);
  923. X        return 0;
  924. X        }
  925. X        if (p = p2) /* set p to p2 and check to see if it's valid */
  926. X        p++;
  927. X    }
  928. X    return 1;
  929. X}
  930. X
  931. X/*
  932. X * Parse arguments specifying days/months/years "ago" (relative to today).
  933. X * Legal syntax: -ago [+-][args]
  934. X *    where "args" is defined to be:
  935. X *    [0-9]+[ ]*[dD][a-Z]*[ ,]*[0-9]+[mM][a-Z]*[ ,]*[0-9]+[ ]*[yY][a-Z]*
  936. X *    1 or more digits, 0 or more spaces, d or D followed by 0 or more chars,
  937. X *    0 or more whitespaces or commas, repeat for months and years...
  938. X * Examples:
  939. X *    1 day, 2 months, 0 years
  940. X *    2 weeks 1 year
  941. X *    10d, 5m
  942. X *    3w
  943. X *    1d 1Y
  944. X *
  945. X * Return number of args parsed; -1 on error.
  946. X */
  947. Xago_date(argv)
  948. Xchar **argv;
  949. X{
  950. X#define SECS_PER_DAY   (60 * 60 * 24)
  951. X#define SECS_PER_WEEK  (SECS_PER_DAY * 7)
  952. X#define SECS_PER_MONTH ((int)(SECS_PER_DAY * 30.5))
  953. X#define SECS_PER_YEAR  (SECS_PER_DAY * 365)
  954. X    register char *p;
  955. X    char       buf[256];
  956. X    int           n = 0, value;
  957. X    long       t;
  958. X    struct tm       *today;
  959. X
  960. X    (void) argv_to_string(buf, argv);
  961. X    p = buf;
  962. X    (void) time (&t); /* get current time in seconds and subtract new values */
  963. X    if (*p == '-')
  964. X    before = TRUE;
  965. X    else if (*p == '+')
  966. X    after = TRUE;
  967. X    skipspaces(before || after);
  968. X    while (*p) {
  969. X    if (!isdigit(*p))
  970. X        break; /* really a syntax error, but it could be other pick args */
  971. X    p = my_atoi(p, &value); /* get 1 or more digits */
  972. X    skipspaces(0); /* 0 or more spaces */
  973. X    switch (lower(*p)) {   /* d, m, or y */
  974. X        case 'd' : t -= value * SECS_PER_DAY;
  975. X        when 'w' : t -= value * SECS_PER_WEEK;
  976. X        when 'm' : t -= value * SECS_PER_MONTH;
  977. X        when 'y' : t -= value * SECS_PER_YEAR;
  978. X        otherwise: return -1;
  979. X    }
  980. X    for (p++; Lower(*p) >= 'a' && *p <= 'z'; p++)
  981. X        ; /* skip the rest of this token */
  982. X    while (*p == ',' || isspace(*p))
  983. X        ; /* 0 or more whitespaces or commas */
  984. X    }
  985. X    today = localtime(&t);
  986. X    mdy[0] = today->tm_mon;
  987. X    mdy[1] = today->tm_mday;
  988. X    mdy[2] = today->tm_year;
  989. X
  990. X    /* Count the number of args parsed */
  991. X    for (n = 0; p > buf && *argv; n++)
  992. X    p -= (strlen(*argv++)+1);
  993. X    Debug("parsed %d args\n", n);
  994. X    return n;
  995. X}
  996. END_OF_FILE
  997. if test 13226 -ne `wc -c <'pick.c'`; then
  998.     echo shar: \"'pick.c'\" unpacked with wrong size!
  999. fi
  1000. # end of 'pick.c'
  1001. fi
  1002. if test -f 'select.c' -a "${1}" != "-c" ; then 
  1003.   echo shar: Will not clobber existing file \"'select.c'\"
  1004. else
  1005. echo shar: Extracting \"'select.c'\" \(13038 characters\)
  1006. sed "s/^X//" >'select.c' <<'END_OF_FILE'
  1007. X/* select.c    (c) copyright 1986 (Dan Heller) */
  1008. X
  1009. X/* 
  1010. X * Routine which handle io (selection on file descriptors) between user and
  1011. X * the various windows.
  1012. X *
  1013. X * In toolmode, the user types characters and each character is interpreted
  1014. X * here and, if applicable, is sent to rite.c where it is appended to a 
  1015. X * string similar to a tty driver and fgets. When the user types a '\n' the
  1016. X * rite() routine returns the string and we call add_to_letter to append the
  1017. X * string to the letter.  Signals are caught here as well.  that is the signal
  1018. X * characters setup by the user are checked and if one matches, call the signal
  1019. X * handling routine as if there were a real signal.
  1020. X *
  1021. X * Mouse handling is done here. See code for more detail.
  1022. X */
  1023. X#include "mush.h"
  1024. X
  1025. X#define READ_MSG    (char *)'r'
  1026. X#define DEL_MSG        (char *)'d'
  1027. X#define UNDEL_MSG    (char *)'u'
  1028. X#define REPL_MSG    (char *)'R'
  1029. X#define SAVE_MSG    (char *)'s'
  1030. X#define PRNT_MSG    (char *)'p'
  1031. X#define PRE_MSG        (char *)'P'
  1032. X#define E_EDIT         (char *)'e'
  1033. X#define E_VIEW         (char *)'v'
  1034. X#define E_INCLUDE      (char *)'i'
  1035. X#define E_SEND        (char *)'S'
  1036. X#define E_ABORT       (char *)'a'
  1037. X#define MENU_HELP    (char *)'h'
  1038. X#define O_SAVE        (char *)'s'
  1039. X#define O_QUIT        (char *)'q'
  1040. X#define O_RSTR        (char *)'r'
  1041. X
  1042. X#define N_MENU_ITEMS    8
  1043. X#define E_MENU_ITEMS    6
  1044. X
  1045. Xmsg_io(gfxsw, ibits, obits, ebits, timer)
  1046. Xregister struct gfxsubwindow *gfxsw;
  1047. Xregister int *ibits,*obits,*ebits;
  1048. Xstruct timeval **timer;
  1049. X{
  1050. X    register char    *p;
  1051. X    struct inputevent     event;
  1052. X    static char     lastchar;
  1053. X    static int         line, count;
  1054. X
  1055. X    if (*ibits & ~(1 << gfxsw->gfx_windowfd)) {
  1056. X    *ibits = *obits = *ebits = 0;
  1057. X    return;
  1058. X    }
  1059. X    if (input_readevent(msg_sw->ts_windowfd, &event) == -1) {
  1060. X    error("input event");
  1061. X    return;
  1062. X    }
  1063. X    /*
  1064. X    if (ID == LOC_WINENTER) {
  1065. X    int x;
  1066. X    struct inputmask im;
  1067. X    win_getinputmask(gfxsw->gfx_windowfd, &im, &x);
  1068. X    win_setinputmask(hdr_sw->ts_windowfd, &im, &im, x);
  1069. X    }
  1070. X    */
  1071. X    if (ID >= KEY_LEFTFIRST)
  1072. X    if (ison(glob_flags, IS_GETTING))
  1073. X        print("Finish editing letter first");
  1074. X    else
  1075. X        (void) func_key(ID);
  1076. X    else if (isascii(ID) && (msg_pix || ison(glob_flags, IS_GETTING) ||
  1077. X    getting_opts)) {
  1078. X    if (getting_opts) {
  1079. X        /*
  1080. X         * txt.x <= 5 indicates not to accept typed input for options
  1081. X         * and function key setting.
  1082. X         */
  1083. X        if (txt.x > 5) {
  1084. X        /* ^C, ^\ or ^U kills line */
  1085. X        type_cursor(PIX_XOR);
  1086. X        if (ID == tchars.t_intrc || ID == tchars.t_quitc ||
  1087. X                        ID == _tty.sg_kill) {
  1088. X            rite(_tty.sg_kill), txt.x = 5;
  1089. X            if (getting_opts == 1)
  1090. X            option_line(line), display_opts(0);
  1091. X            else
  1092. X            set_key(0, 0, 0);
  1093. X        } else if (p = rite((char)ID)) {
  1094. X            /* if no string entered, preserve old value */
  1095. X            if (*p && getting_opts == 1)
  1096. X            add_opt(p, line);
  1097. X            if (getting_opts == 2)
  1098. X            set_key(p, 0,0);
  1099. X        } else
  1100. X            type_cursor(PIX_XOR);
  1101. X        }
  1102. X    }
  1103. X    /*
  1104. X     * This section MUST BE BEFORE the following "is_getting" section.
  1105. X     * If user displays a message while editing a letter, he must hit 'q'
  1106. X     * to return to edit mode.  He may not edit a new letter while one is
  1107. X     * already being edited.
  1108. X     */
  1109. X    else if (msg_pix)
  1110. X        if (isdigit(ID)) {
  1111. X        if (!isdigit(lastchar))
  1112. X            count = 0;
  1113. X        count = count * 10 + ID - '0';
  1114. X        } else {
  1115. X        /* scroll <count> lines */
  1116. X        if (!count)
  1117. X            count = 1;
  1118. X        if (ID == 'k' || ID == 'K' || ID == '-')
  1119. X            scroll_win(-count);
  1120. X        else if (ID == '\n' || ID == '\r' || ID == 'j' ||
  1121. X             ID == 'J' || ID == '+')
  1122. X            scroll_win(count);
  1123. X        else if (ID == ' ')
  1124. X            scroll_win(crt-3);
  1125. X        else if ((ID == 'q' || ID == 'Q') &&
  1126. X            ison(glob_flags, IS_GETTING)) {
  1127. X            pr_destroy(msg_pix), msg_pix = (struct pixrect *)NULL;
  1128. X            win_setcursor(msg_sw->ts_windowfd, &write_cursor);
  1129. X            txt.x = 5, txt.y = msg_rect.r_height - l_height(curfont);
  1130. X            wprint("\n(continue editing letter)\n");
  1131. X            clr_bot_line();
  1132. X            type_cursor(PIX_SRC);
  1133. X        }
  1134. X        }
  1135. X    /*
  1136. X     * If msg_pix is NULL, then we are not reading a message. If we are
  1137. X     * editing a letter, then enter the keys typed.  If we are doing
  1138. X     * nothing, ignore this input.
  1139. X     */
  1140. X    else if (ison(glob_flags, IS_GETTING)) {
  1141. X        type_cursor(PIX_XOR);
  1142. X        if (lastchar != ltchars.t_lnextc &&
  1143. X        (ID == tchars.t_intrc || ID == tchars.t_quitc)) {
  1144. X            (void) rite(_tty.sg_kill);
  1145. X            (void) rm_edfile(SIGINT);
  1146. X        } else {
  1147. X        register int n = 1;
  1148. X        if (ID == tchars.t_eofc && txt.x == 5
  1149. X            || (p = rite((char)ID)) && !(n = add_to_letter(p)))
  1150. X            finish_up_letter();
  1151. X        else if (n > 0)
  1152. X            type_cursor(PIX_XOR);
  1153. X        }
  1154. X    }
  1155. X    lastchar = ID;
  1156. X    } else switch(ID) {
  1157. X    when MS_LEFT : case MS_MIDDLE:
  1158. X        if (getting_opts == 2)
  1159. X        if (ID == MS_LEFT)
  1160. X            set_key(NULL, event.ie_locx, event.ie_locy);
  1161. X        else {
  1162. X            register char *p = find_key(event.ie_locx, event.ie_locy);
  1163. X            if (p)
  1164. X            print("Function key %s:  %s", p, key_set_to(p));
  1165. X        }
  1166. X        else if (getting_opts) {
  1167. X        int y = event.ie_locy - 50;
  1168. X        if (y < -24)
  1169. X            break;
  1170. X        if (y < 0) {
  1171. X            register int x = event.ie_locx;
  1172. X            register int X = 60*l_width(LARGE);
  1173. X            if (x >= X && x <= X+16)
  1174. X            display_opts(-1); /* scroll options back one value */
  1175. X            else if (x >= X+20 && x <= X+36)
  1176. X            display_opts(1); /* scroll options forward one value */
  1177. X            break;
  1178. X        }
  1179. X        /* the user was typing something -- stopped by using mouse */
  1180. X        if (txt.x > 5) {
  1181. X            type_cursor(PIX_CLR);
  1182. X            (void) rite(_tty.sg_kill), txt.x = 5;
  1183. X            option_line(line), display_opts(0);
  1184. X        }
  1185. X            line = y/20;
  1186. X        if (ID == MS_LEFT)
  1187. X            toggle_opt(line);
  1188. X        help_opt(line);   /* display help (short info) in both cases */
  1189. X        } else if (msg_pix)
  1190. X        if (ID == MS_LEFT)
  1191. X            scroll_win(crt-3);
  1192. X        else
  1193. X            scroll_win(-(crt-3));
  1194. X    when MS_RIGHT:
  1195. X        if (getting_opts)
  1196. X        (void) view_opts_menu(&event, gfxsw->gfx_windowfd);
  1197. X        else if (isoff(glob_flags, IS_GETTING))
  1198. X        (void) do_menu(&event, gfxsw->gfx_windowfd, current_msg);
  1199. X        else
  1200. X        (void) edit_menu(&event, gfxsw->gfx_windowfd);
  1201. X    otherwise: ;
  1202. X    }
  1203. X    *ibits = *obits = *ebits = 0;
  1204. X}
  1205. X
  1206. Xstruct cursor *mice[3] = { &l_cursor, &m_cursor, &r_cursor };
  1207. X
  1208. Xhdr_io(gfxsw, ibits, obits, ebits, sw_timer)
  1209. Xregister struct gfxsubwindow *gfxsw;
  1210. Xint *ibits,*obits,*ebits;
  1211. Xstruct timeval **sw_timer;
  1212. X{
  1213. X    static int         which_cursor;
  1214. X    struct inputmask     im;
  1215. X    struct inputevent     event;
  1216. X    int         line;
  1217. X
  1218. X    if (*ibits & ~(1 << gfxsw->gfx_windowfd)) {
  1219. X    *ibits = *obits = *ebits = 0;
  1220. X    return;
  1221. X    }
  1222. X    /* make curosr change which button is lit */
  1223. X    win_setcursor(gfxsw->gfx_windowfd, mice[which_cursor]);
  1224. X
  1225. X    which_cursor = (which_cursor+1) % 3;
  1226. X    if (input_readevent(hdr_sw->ts_windowfd, &event) == -1) {
  1227. X    error("input event");
  1228. X    return;
  1229. X    }
  1230. X    /* I'm not sure why I have to do this.
  1231. X     * I'm doing it because sometimes the IO hangs completely and no input
  1232. X     * is accepted. What I do here is get the current mask, save it, then
  1233. X     * reset it. This action seems to flush the IO queue, and I don't have hung
  1234. X     * IO anymore.  This shouldn't be necessary, but it appears to work.
  1235. X     * (occurances have droped about 90%)
  1236. X     */
  1237. X    if (ID == LOC_WINENTER) {
  1238. X    int x;
  1239. X    win_getinputmask(gfxsw->gfx_windowfd, &im, &x);
  1240. X    win_setinputmask(hdr_sw->ts_windowfd, &im, &im, x);
  1241. X    }
  1242. X    /* just return -- we just wanted to make the cursor flicker */
  1243. X    if (ID == LOC_STILL || ID == LOC_MOVE || ID == LOC_WINENTER) {
  1244. X    *ibits = *obits = *ebits = 0;
  1245. X    return;
  1246. X    }
  1247. X    line = event.ie_locy / l_height(DEFAULT);
  1248. X    if (ID >= KEY_LEFTFIRST)
  1249. X    (void) func_key(ID);
  1250. X    else if (n_array[line] > msg_cnt)
  1251. X    if (!msg_cnt)
  1252. X        print("-- You have no messages -- ");
  1253. X    else
  1254. X        print("Message out of range.  Place mouse over a legal message.");
  1255. X    else switch(ID) {
  1256. X    when MS_LEFT: case MS_MIDDLE:
  1257. X        (void) do_menu((ID == MS_LEFT)? READ_MSG: DEL_MSG, 0,n_array[line]);
  1258. X    when MS_RIGHT:
  1259. X        (void) do_menu(&event, gfxsw->gfx_windowfd, n_array[line]);
  1260. X    otherwise : print("Unkown ID = %d", ID);
  1261. X    }
  1262. X    *ibits = *obits = *ebits = 0;
  1263. X}
  1264. X
  1265. X/* if "fd" is 0, then event points to the action to be taken.
  1266. X * otherwise, determine action to be taken by displaying a menu.
  1267. X * message is the number current_msg should be changed to (may be the same).
  1268. X */
  1269. Xdo_menu(event, fd, message)
  1270. Xcaddr_t event;
  1271. X{
  1272. X    static char buf[20];
  1273. X    struct menuitem *m_item;
  1274. X    char *action;
  1275. X    static struct menuitem msg_menu_items[] = {
  1276. X    { MENU_IMAGESTRING,  "Read",     READ_MSG   },
  1277. X    { MENU_IMAGESTRING,  "Delete",   DEL_MSG    },
  1278. X    { MENU_IMAGESTRING,  "Undelete", UNDEL_MSG  },
  1279. X    { MENU_IMAGESTRING,  "Reply",    REPL_MSG   },
  1280. X    { MENU_IMAGESTRING,  "Save",     SAVE_MSG   },
  1281. X    { MENU_IMAGESTRING,  "Preserve", PRE_MSG    },
  1282. X    { MENU_IMAGESTRING,  "Print",    PRNT_MSG   },
  1283. X    { MENU_IMAGESTRING,  "Help",     MENU_HELP  }
  1284. X    };
  1285. X    static struct menu help_menu = {
  1286. X        MENU_IMAGESTRING, "Item Help",
  1287. X    N_MENU_ITEMS, msg_menu_items,
  1288. X    (struct menu *)NULL, NULL
  1289. X    };
  1290. X    static struct menu msgs_menu = {
  1291. X        MENU_IMAGESTRING, buf, N_MENU_ITEMS,
  1292. X    msg_menu_items, &help_menu, NULL
  1293. X    };
  1294. X    /* to have the menu stack maintain order of menus upon each invokation,
  1295. X     * declare menu_ptr to be static and remove the following two lines
  1296. X     * after the declaration.
  1297. X     */
  1298. X    struct menu *menu_ptr = &msgs_menu;
  1299. X    msgs_menu.m_next = &help_menu;
  1300. X    help_menu.m_next = (struct menu *)NULL;
  1301. X
  1302. X    if (!msg_cnt) {
  1303. X    print("No Messages.");
  1304. X    return;
  1305. X    }
  1306. X    if (fd) {
  1307. X    (void) sprintf(buf, "Message #%d", message+1);
  1308. X    if (m_item = menu_display(&menu_ptr, (struct inputevent *)event, fd))
  1309. X        action = m_item->mi_data;
  1310. X    else
  1311. X        return;
  1312. X    } else
  1313. X    action = event;
  1314. X
  1315. X    if (menu_ptr == &help_menu || action == MENU_HELP) {
  1316. X    switch(action) {
  1317. X        when DEL_MSG: case UNDEL_MSG:
  1318. X        (void) help(fd, "menu_delete", tool_help);
  1319. X        when READ_MSG: (void) help(fd, "next", tool_help);
  1320. X        when REPL_MSG: (void) help(fd, "menu_respond", tool_help);
  1321. X        when SAVE_MSG: (void) help(fd, "save", tool_help);
  1322. X        when PRE_MSG: (void)  help(fd, "preserve", tool_help);
  1323. X        when PRNT_MSG: (void) help(fd, "printer", tool_help);
  1324. X        when MENU_HELP:
  1325. X        if (menu_ptr == &help_menu)
  1326. X            (void) help(fd, "help_menu_help_msg", tool_help);
  1327. X        else
  1328. X            (void) help(fd, "msg_menu", tool_help);
  1329. X    }
  1330. X    return;
  1331. X    }
  1332. X    set_isread(message);
  1333. X    if (action == SAVE_MSG) {
  1334. X    panel_set(msg_num_item, PANEL_VALUE, sprintf(buf, "%d", message+1), 0);
  1335. X    ((struct inputevent *)event)->ie_code = MS_LEFT;
  1336. X    do_file_dir(save_item, 0, event);
  1337. X    panel_set(msg_num_item, PANEL_VALUE, NO_STRING, 0);
  1338. X    return;
  1339. X    } else if (action == PRNT_MSG  || action == PRE_MSG ||
  1340. X           action == UNDEL_MSG || action == DEL_MSG) {
  1341. X    fkey_misc(action, message);
  1342. X    return;
  1343. X    }
  1344. X    if (isoff(glob_flags, IS_GETTING)) {
  1345. X    current_msg = message;
  1346. X    (void) do_hdrs(0, DUBL_NULL, NULL);
  1347. X    }
  1348. X    if (action == REPL_MSG) {
  1349. X    respond_mail(respond_item, 0, event);
  1350. X    return;
  1351. X    } else if (ison(glob_flags, IS_GETTING)) {
  1352. X    if (exec_pid)
  1353. X        /* User can read a message as long as he's not in an editor */
  1354. X        print("Finish editing message first");
  1355. X    else {
  1356. X        (void) do_hdrs(0, DUBL_NULL, NULL);
  1357. X        display_msg(message, (long)0);
  1358. X    }
  1359. X    return;
  1360. X    }
  1361. X    display_msg(current_msg, (long)0);
  1362. X}
  1363. X
  1364. X/* miscellaneous function key actions there are here because the defines
  1365. X * for DEL_MSG, etc are here in this file and the function is called from
  1366. X * here more often.
  1367. X */
  1368. Xfkey_misc(action, message)
  1369. Xchar *action;
  1370. X{
  1371. X    int argc;
  1372. X    register char **argv;
  1373. X    char buf[30];
  1374. X
  1375. X    print("Message #%d ", message+1);
  1376. X    if (action == UNDEL_MSG || action == DEL_MSG)
  1377. X    print_more("%sd. ", sprintf(buf, "%selete",
  1378. X                (action == DEL_MSG)? "d": "und"));
  1379. X    else if (action == PRNT_MSG) {
  1380. X    print_more("sent to printer");
  1381. X    (void) strcpy(buf, "lpr");
  1382. X    } else if (action == PRE_MSG)
  1383. X    print_more("%sd", strcpy(buf, "preserve"));
  1384. X    (void) sprintf(&buf[strlen(buf)], " %d", message+1);
  1385. X    if (message == current_msg && action == DEL_MSG)
  1386. X    do_clear();
  1387. X
  1388. X    if (argv = make_command(buf, DUBL_NULL, &argc))
  1389. X    (void) do_command(argc, argv, msg_list);
  1390. X    return;
  1391. X}
  1392. X
  1393. Xview_opts_menu(event, fd)
  1394. Xstruct inputevent *event;
  1395. X{
  1396. X    static char buf[5];
  1397. X    struct menuitem *m_item;
  1398. X    char *action;
  1399. X    static struct menuitem opts_items[] = {
  1400. X    { MENU_IMAGESTRING,  "Save Options",    O_SAVE  },
  1401. X    { MENU_IMAGESTRING,  "Restore Options",    O_RSTR  },
  1402. X    { MENU_IMAGESTRING,  "Quit Options",    O_QUIT  },
  1403. X    { MENU_IMAGESTRING,  "Help",        MENU_HELP  }
  1404. X    };
  1405. X    static struct menu msgs_menu = {
  1406. X        MENU_IMAGESTRING, "Options", 4, opts_items, (struct menu *)NULL, NULL
  1407. X    };
  1408. X    struct menu *menu_ptr = &msgs_menu;
  1409. X
  1410. X    if (m_item = menu_display(&menu_ptr, event, fd))
  1411. X    action = m_item->mi_data;
  1412. X    else
  1413. X    return;
  1414. X    switch(action) {
  1415. X    case O_SAVE:
  1416. X        save_opts(0, DUBL_NULL);
  1417. X    when O_RSTR:
  1418. X        init();
  1419. X        if (getting_opts == 1)
  1420. X        view_options();
  1421. X        else
  1422. X        set_fkeys();
  1423. X    when O_QUIT:
  1424. X        do_clear();
  1425. X        unlock_cursors(); /* actually resets msg_win's cursor */
  1426. X        if (isoff(glob_flags, IS_GETTING) && msg_cnt)
  1427. X        if (isoff(msg[current_msg].m_flags, DELETE))
  1428. X            display_msg(current_msg, (long)0);
  1429. X        else
  1430. X            (void) read_mail(NO_ITEM, 0, NO_EVENT);
  1431. X    when MENU_HELP:
  1432. X        (void) help(fd, (getting_opts == 1)? "options": "fkeys", tool_help);
  1433. X    }
  1434. X}
  1435. END_OF_FILE
  1436. if test 13038 -ne `wc -c <'select.c'`; then
  1437.     echo shar: \"'select.c'\" unpacked with wrong size!
  1438. fi
  1439. # end of 'select.c'
  1440. fi
  1441. if test -f 'viewopts.c' -a "${1}" != "-c" ; then 
  1442.   echo shar: Will not clobber existing file \"'viewopts.c'\"
  1443. else
  1444. echo shar: Extracting \"'viewopts.c'\" \(13307 characters\)
  1445. sed "s/^X//" >'viewopts.c' <<'END_OF_FILE'
  1446. X/* @(#)viewopts.c    (c) copyright    10/18/86 (Dan Heller) */
  1447. X
  1448. X#include "mush.h"
  1449. X
  1450. Xstruct viewopts {
  1451. X    char *v_opt;
  1452. X    char *v_prompt;
  1453. X    int  v_usage;
  1454. X#define TOOL  01
  1455. X#define TEXT  02
  1456. X    char *v_description;
  1457. X};
  1458. X
  1459. X/*
  1460. X * struct contains the option, a prompt if it has a string value, whether
  1461. X * or not it applies to non suntools, line mode, or both, and a
  1462. X * string describing what the option does. If the prompt string starts
  1463. X * with a minus sign, then the value can be set without a value. This
  1464. X * is there to indicate to option_line to print a toggle (cycle) pixrect
  1465. X * and to print TRUE/FALSE telling whether the value is on or off regardless
  1466. X * of it's "string" value.
  1467. X */
  1468. Xstruct viewopts viewopts[] = {
  1469. X    { "alwaysignore", NULL, TOOL | TEXT,
  1470. X    "Always ignore the message headers on the 'ignored' list." },
  1471. X    { "ask", NULL, TOOL | TEXT,
  1472. X    "Prompts for a subject on outgoing mail." },
  1473. X    { "askcc", NULL, TOOL | TEXT,
  1474. X    "Ask for list of Carbon Copy recipients whenever sending mail." },
  1475. X    { "autodelete", NULL, TOOL | TEXT,
  1476. X    "Automatically delete ALL READ messages whenever you update mail." },
  1477. X    { "autoedit", NULL, TOOL | TEXT,
  1478. X    "Automatically enter editor whenever you REPLY to mail." },
  1479. X    { "autoinclude", NULL, TOOL | TEXT,
  1480. X    "Include a copy of author's message each time you reply to mail." },
  1481. X    { "autoprint", NULL, TOOL | TEXT,
  1482. X    "Display the next message on the list when you delete a message." },
  1483. X    { "auto_route", NULL, TOOL | TEXT,
  1484. X    "Remove redundant uucp addresses when replying to messages." },
  1485. X    { "autosign", "-Filename", TOOL | TEXT,
  1486. X    "Add file (~/.signature if set but no value) at end of all letters." },
  1487. X    { "autosign2", "Address : Filename", TOOL | TEXT,
  1488. X    "Signature to use for specific addresses. \"addr, ... : <signature>\""},
  1489. X    { "cdpath", "Path", TEXT,
  1490. X    "Path to search for directories when the \"cd\" command is issued." },
  1491. X    { "crt", "Lines", TEXT,
  1492. X    "The number of lines a message must have for 'pager' to be invoked." },
  1493. X    { "date_received", NULL, TOOL | TEXT,
  1494. X    "Time displayed for message headers shows date received (or sent)." },
  1495. X    { "dead", "Filename", TOOL | TEXT,
  1496. X    "The name of the file to store dead mail (default = ~/dead.letter)." },
  1497. X    { "dot", NULL, TOOL | TEXT,
  1498. X    "Allow \".\" on a line by itself to send letter." },
  1499. X    { "editor", "Editor name/path", TOOL | TEXT,
  1500. X    "Editor for message editing (default = env EDITOR or \"vi\")." },
  1501. X    { "escape", "Character", TOOL | TEXT,
  1502. X    "Escape character for extended editing commands (default = ~)." },
  1503. X    { "folder", "Pathname", TOOL | TEXT,
  1504. X    "Full pathname to the directory where personal folders are kept." },
  1505. X    { "fortune", "-Flag", TOOL | TEXT,
  1506. X    "Add fortune to end of letters.  Flag to \"fortune\" is optional." },
  1507. X    { "fortunates", "Users", TOOL | TEXT,
  1508. X    "Those who will receive fortunes if fortune is set (default: All)." },
  1509. X    { "hdr_format", "Format", TOOL | TEXT,
  1510. X    "Formatting string for headers.  \"headers -?\" or help hdr_format." },
  1511. X    { "history", "Number", TEXT,
  1512. X    "How many commands to remember (like csh)." },
  1513. X    { "hold", NULL, TOOL | TEXT,
  1514. X    "Read but not deleted messages are saved in spool -- not mbox." },
  1515. X    { "home", "Directory", TOOL | TEXT,
  1516. X    "The user's home directory." },
  1517. X    { "hostname", "Hostname", TOOL | TEXT,
  1518. X    "User-definable name for the name of your machine." },
  1519. X    { "ignore_bang", NULL, TEXT,
  1520. X    "Ignore '!' as a history reference.  Otherwise, escape by: \\!" },
  1521. X    { "ignoreeof", "-Command", TEXT,
  1522. X    "Ignores ^D as exit, or (if set), execute \"command\"." },
  1523. X    { "indent_str", "String", TOOL | TEXT,
  1524. X    "String to offset included messages within your letters." },
  1525. X    { "in_reply_to", NULL, TOOL | TEXT,
  1526. X    "When responding to mail, add In-Reply-To: to message headers." },
  1527. X    { "keepsave", NULL, TOOL | TEXT,
  1528. X    "Prevents messages from being marked as `deleted' when you `save'." },
  1529. X    { "known_hosts", "Host list", TOOL | TEXT,
  1530. X    "List of hosts that your site is known to uucp mail to." },
  1531. X    { "lister", "Arguments", TOOL | TEXT,
  1532. X    "Arguments passed to the 'ls' command." },
  1533. X    { "logfile", "Filename", TOOL | TEXT,
  1534. X    "Log outgoing mail headers only.  Message text not logged." },
  1535. X    { "mbox", "Filename", TOOL | TEXT,
  1536. X    "Filename to use instead of ~/mbox for default mailbox." },
  1537. X    { "metoo", NULL, TOOL | TEXT,
  1538. X    "When replying to mail, metoo preserves your name on mailing list." },
  1539. X    { "mil_time", NULL, TOOL | TEXT,
  1540. X    "24-hour military time format is used whenever a time is printed. " },
  1541. X    { "newline", "-Command", TEXT,
  1542. X    "Ignore RETURN.  If set to a command, execute that command." },
  1543. X    { "no_expand", NULL, TEXT | TOOL,
  1544. X    "Prevents expansion of Mush aliases in outgoing mail headers." },
  1545. X    { "no_hdrs", NULL, TOOL | TEXT,
  1546. X    "If set, personalized headers are NOT inserted to outgoing mail." },
  1547. X    { "no_reverse", NULL, TOOL | TEXT,
  1548. X    "Disables reverse video in curses mode -- uses \"bold\" in tool mode."},
  1549. X    { "nonobang", NULL, TEXT,
  1550. X    "Suppresses errors from unsuccessful history references." },
  1551. X    { "nosave", NULL, TOOL | TEXT,
  1552. X    "Prevents aborted mail from being saved in $dead." },
  1553. X    { "pager", "Program", TEXT,
  1554. X    "Program name to be used as a pager for messages longer than crt." },
  1555. X    { "pre_indent_str", "String", TEXT | TOOL,
  1556. X    "String to precede message text interpolated into message body." },
  1557. X    { "post_indent_str", "String", TEXT | TOOL,
  1558. X    "String to succeed message text interpolated into message body." },
  1559. X    { "print_cmd", "Program", TOOL | TEXT,
  1560. X    "Alternate program to use to send messages to the printer." },
  1561. X    { "printer", "Printer", TOOL | TEXT,
  1562. X    "Printer to send messages to (default = environment PRINTER)." },
  1563. X    { "prompt", "String", TEXT,
  1564. X    "Your prompt.  \"help prompt\" for more information." },
  1565. X    { "quiet", NULL, TEXT,
  1566. X    "Don't print the version number of Mush on startup." },
  1567. X    { "realname", "Name:", TOOL | TEXT,
  1568. X    "Your real name." },
  1569. X    { "record", "Filename", TOOL | TEXT,
  1570. X    "Save all outgoing mail in specified filename." },
  1571. X    { "reply_to_hdr", "Headers", TOOL | TEXT,
  1572. X    "List of headers use to construct reply addresses from a message." },
  1573. X    { "save_empty", NULL, TOOL | TEXT,
  1574. X    "Folders which have all messages deleted are NOT removed on updates." },
  1575. X    { "screen", "Number of Headers", TEXT,
  1576. X    "Number of headers to print in non-suntools (text) mode." },
  1577. X    { "screen_win", "Number of Headers", TOOL,
  1578. X    "Set the size of the header window for the tool mode only." },
  1579. X    { "show_deleted", NULL, TOOL | TEXT,
  1580. X    "Show deleted messages in headers listings (unused in curses mode)." },
  1581. X    { "show_hdrs", "Headers", TOOL | TEXT,
  1582. X    "When displaying a message, show list of \"headers\" only." },
  1583. X    { "sendmail", "Program", TOOL | TEXT,
  1584. X    "Program to use to deliver mail instead of using the default."},
  1585. X    { "sort", "-Option", TOOL | TEXT,
  1586. X    "Pre-sorting of messages on mush startup (set to valid sort option)." },
  1587. X    { "squeeze", NULL, TOOL | TEXT,
  1588. X    "When reading messages, squeeze all blank lines into one." },
  1589. X    { "thisfolder", NULL, TEXT,
  1590. X    "This read-only variable gives the current folder name." },
  1591. X    { "toplines", "Lines", TOOL | TEXT,
  1592. X    "Number of lines to print of a message for the 'top' command."  },
  1593. X    { "tmpdir", "Directory", TOOL | TEXT,
  1594. X    "Directory to use for temporary files used by Mush." },
  1595. X    { "unix", NULL, TEXT,
  1596. X    "Non-mush commands are considered to be UNIX commands." },
  1597. X    { "verify", NULL, TEXT,
  1598. X    "Verify to send, re-edit, or abort letter after editing." },
  1599. X    { "visual", "Visual editor", TOOL | TEXT,
  1600. X    "Visual editor for messages (default = $editor or env VISUAL)."},
  1601. X    { "warning", NULL, TOOL | TEXT,
  1602. X    "Print warning messages for non-fatal errors." },
  1603. X    { "wrap", NULL, TOOL | TEXT,
  1604. X    "After referencing last message, message pointer wraps to start." },
  1605. X    { "wrapcolumn", "-Column to wrap [78]", TEXT,
  1606. X    "Column at which to wrap lines when composing messages." },
  1607. X};
  1608. X
  1609. X#define total_opts (sizeof viewopts / sizeof (struct viewopts))
  1610. X
  1611. X#ifdef SUNTOOL
  1612. X
  1613. Xstatic int start_cnt;
  1614. X
  1615. X#define twenty     5 + 20*l_width(DEFAULT)
  1616. X#define forty     5 + 40*l_width(DEFAULT)
  1617. X#define image_at(x,y,image) pw_rop(msg_win, x, y, 16, 16, PIX_SRC, image, 0,0)
  1618. X
  1619. X/* print in default text, but increment in large text segments */
  1620. Xview_options()
  1621. X{
  1622. X    if (msg_rect.r_height < 80) {
  1623. X    print("Window not big enough to display options.");
  1624. X    return;
  1625. X    }
  1626. X    do_clear();
  1627. X    getting_opts = 1, start_cnt = 0;
  1628. X    win_setcursor(msg_sw->ts_windowfd, &checkmark);
  1629. X    highlight(msg_win, txt.x, txt.y, LARGE,
  1630. X        "    : Toggle Value       : Description       : Menu (Help)");
  1631. X    image_at(txt.x +  2 * l_width(DEFAULT), txt.y - 12, &mouse_left);
  1632. X    image_at(txt.x + 25 * l_width(DEFAULT), txt.y - 12, &mouse_middle);
  1633. X    image_at(txt.x + 48 * l_width(DEFAULT), txt.y - 12, &mouse_right);
  1634. X
  1635. X    pw_vector(msg_win, 0, txt.y+6, msg_rect.r_width, txt.y+6, PIX_SRC, 1);
  1636. X    pw_vector(msg_win, 0, txt.y+8, msg_rect.r_width, txt.y+8, PIX_SRC, 1);
  1637. X
  1638. X    txt.y += 24;
  1639. X
  1640. X    pw_text(msg_win, 5,      txt.y, PIX_SRC, fonts[LARGE], "Option");
  1641. X    pw_text(msg_win, twenty, txt.y, PIX_SRC, fonts[LARGE], "On/Off");
  1642. X    pw_text(msg_win, forty,  txt.y, PIX_SRC, fonts[LARGE], "Values");
  1643. X
  1644. X    pw_vector(msg_win, 0, txt.y+6, msg_rect.r_width, txt.y+6, PIX_SRC, 1);
  1645. X    pw_vector(msg_win, 0, txt.y+8, msg_rect.r_width, txt.y+8, PIX_SRC, 1);
  1646. X
  1647. X    pw_text(msg_win, 59*l_width(DEFAULT),txt.y,PIX_SRC,fonts[LARGE],"Scroll:");
  1648. X    pw_rop(msg_win, 60*l_width(LARGE), txt.y-13,16,16,PIX_SRC, &dn_arrow,0,0);
  1649. X    pw_rop(msg_win, 60*l_width(LARGE)+20,txt.y-13,16,16,PIX_SRC, &up_arrow,0,0);
  1650. X
  1651. X    display_opts(0); /* create the pixrect and all that */
  1652. X}
  1653. X
  1654. Xdisplay_opts(count)
  1655. Xregister int count;
  1656. X{
  1657. X    register int total_displayable = (msg_rect.r_height - 60) / 20;
  1658. X
  1659. X    if (count < 0 && start_cnt + count < 0) {
  1660. X    print("At the beginning");
  1661. X    return;
  1662. X    } else if (count && start_cnt + count + total_displayable > total_opts) {
  1663. X    print("At the end");
  1664. X    return;
  1665. X    }
  1666. X    start_cnt += count;
  1667. X    if (!msg_pix) {
  1668. X    register int x = (total_opts+1) * 20;
  1669. X    if (x < msg_rect.r_height)
  1670. X        x = msg_rect.r_height;
  1671. X    if (!(msg_pix = mem_create(msg_rect.r_width, x, 1))) {
  1672. X        error("mem_create");
  1673. X        return;
  1674. X    }
  1675. X    pr_rop(msg_pix,0,0, msg_rect.r_width-1, x-1, PIX_CLR,0,0,0);
  1676. X    for (count = 0; count < total_opts; count++)
  1677. X        option_line(count);
  1678. X    }
  1679. X    pw_rop(msg_win, 0, 50, msg_rect.r_width - 1, msg_rect.r_height - 50,
  1680. X       PIX_SRC, msg_pix, 0, start_cnt * 20);
  1681. X}
  1682. X
  1683. Xvoid
  1684. Xtoggle_opt(line)
  1685. X{
  1686. X    register char *p = viewopts[start_cnt+line].v_prompt;
  1687. X
  1688. X    if (do_set(set_options, viewopts[start_cnt+line].v_opt))
  1689. X    un_set(&set_options, viewopts[start_cnt+line].v_opt);
  1690. X    else {
  1691. X    if (p) {
  1692. X        txt.x = 5 + 40 * l_width(DEFAULT) +
  1693. X            (1 + strlen(p) - (*p=='-')) * l_width(DEFAULT);
  1694. X        txt.y = 50 + line*20 + l_height(curfont);
  1695. X    }
  1696. X    if (!p || *p == '-') {
  1697. X        register char *argv[2];
  1698. X        argv[0] = viewopts[start_cnt+line].v_opt;
  1699. X        argv[1] = NULL;
  1700. X        (void) add_option(&set_options, argv);
  1701. X    }
  1702. X    }
  1703. X    option_line(line);
  1704. X    display_opts(0);
  1705. X    if (txt.x > 5)
  1706. X    type_cursor(PIX_SRC);
  1707. X}
  1708. X
  1709. Xvoid
  1710. Xhelp_opt(line)
  1711. X{
  1712. X    print(viewopts[start_cnt+line].v_description);
  1713. X}
  1714. X
  1715. Xadd_opt(p, line)
  1716. Xregister char *p;
  1717. X{
  1718. X    char buf[80], **argv;
  1719. X    int argc;
  1720. X    u_long save_bang = ison(glob_flags, IGN_BANG);
  1721. X
  1722. X    (void) sprintf(buf, "set %s=\"%s\"", viewopts[start_cnt+line].v_opt, p);
  1723. X    turnon(glob_flags, IGN_BANG);
  1724. X    if (argv = make_command(buf, DUBL_NULL, &argc))
  1725. X    (void) do_command(argc, argv, msg_list);
  1726. X    if (!save_bang)
  1727. X    turnoff(glob_flags, IGN_BANG);
  1728. X    option_line(line); /* make sure new value is entered into database */
  1729. X}
  1730. X
  1731. Xoption_line(count)
  1732. Xregister int count;
  1733. X{
  1734. X    register char *p, *v = do_set(set_options, viewopts[start_cnt+count].v_opt);
  1735. X    struct pr_prpos win;
  1736. X
  1737. X    win.pr = msg_pix;
  1738. X    win.pos.y = (start_cnt + count) * 20 + 16;
  1739. X    win.pos.x = 5;
  1740. X
  1741. X    pf_text(win, PIX_SRC, fonts[DEFAULT], blank);
  1742. X    pf_text(win, PIX_SRC, fonts[DEFAULT], viewopts[start_cnt+count].v_opt);
  1743. X    win.pos.x = twenty+20;
  1744. X
  1745. X    if (!(p = viewopts[start_cnt+count].v_prompt) || *p == '-') {
  1746. X    pr_rop(msg_pix, twenty, win.pos.y-10, 16, 16, PIX_SRC, &cycle, 0, 0);
  1747. X    pf_text(win, PIX_SRC, fonts[DEFAULT], (v)? "TRUE  ": "FALSE");
  1748. X    win.pos.x++;
  1749. X    pf_text(win, PIX_SRC, fonts[DEFAULT], (v)? "TRUE  ": "FALSE");
  1750. X    }
  1751. X    if (p) {
  1752. X    if (*p == '-')
  1753. X        p++;
  1754. X    win.pos.x = forty;
  1755. X    /* highlight */
  1756. X    pf_text(win, PIX_SRC, fonts[DEFAULT], p);
  1757. X    win.pos.x++;
  1758. X    pf_text(win, PIX_SRC, fonts[DEFAULT], p);
  1759. X        win.pos.x = forty + strlen(p) * l_width(DEFAULT);
  1760. X    pf_text(win, PIX_SRC, fonts[DEFAULT], ":");
  1761. X    if (v) {
  1762. X        win.pos.x += (2 * l_width(DEFAULT));
  1763. X        pf_text(win, PIX_SRC, fonts[DEFAULT], v);
  1764. X    }
  1765. X    }
  1766. X}
  1767. X
  1768. X#endif /* SUNTOOL */
  1769. X
  1770. X/*
  1771. X * return a string describing a variable.
  1772. X * parameters: count, str, buf.
  1773. X * If str != NULL, check str against ALL variables
  1774. X * in viewopts array.  The one that matches, set count to it and 
  1775. X * print up all the stuff from the viewopts[count] into the buffer
  1776. X * space in "buf" and return it.
  1777. X */
  1778. Xchar *
  1779. Xvariable_stuff(count, str, buf)
  1780. Xregister char *str, buf[];
  1781. X{
  1782. X    if (str)
  1783. X    for (count = 0; count < total_opts; count++)
  1784. X        if (!strcmp(str, viewopts[count].v_opt))
  1785. X        break;
  1786. X    if (count >= total_opts) {
  1787. X    (void) sprintf(buf, "%s: Not a default %s variable.",
  1788. X               str? str : itoa(count), prog_name);
  1789. X    return NULL;
  1790. X    }
  1791. X    return sprintf(buf, "%s: %s",
  1792. X    viewopts[count].v_opt, viewopts[count].v_description);
  1793. X}
  1794. END_OF_FILE
  1795. if test 13307 -ne `wc -c <'viewopts.c'`; then
  1796.     echo shar: \"'viewopts.c'\" unpacked with wrong size!
  1797. fi
  1798. # end of 'viewopts.c'
  1799. fi
  1800. echo shar: End of archive 6 \(of 19\).
  1801. cp /dev/null ark6isdone
  1802. MISSING=""
  1803. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ; do
  1804.     if test ! -f ark${I}isdone ; then
  1805.     MISSING="${MISSING} ${I}"
  1806.     fi
  1807. done
  1808. if test "${MISSING}" = "" ; then
  1809.     echo You have unpacked all 19 archives.
  1810.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1811. else
  1812.     echo You still need to unpack the following archives:
  1813.     echo "        " ${MISSING}
  1814. fi
  1815. ##  End of shell archive.
  1816. exit 0
  1817.